package com.zsk.shop.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsk.shop.api.pay.common.bean.TransferOrder;
import com.zsk.shop.api.pay.common.util.PayUtil;
import com.zsk.shop.api.pay.wx.bean.WxTransferType;
import com.zsk.shop.common.base.BaseResponse;
import com.zsk.shop.common.base.BizException;
import com.zsk.shop.common.base.page.BasePageFactory;
import com.zsk.shop.common.constant.Constant;
import com.zsk.shop.common.utils.*;
import com.zsk.shop.config.pay.WeixinPayConfig;
import com.zsk.shop.entity.*;
import com.zsk.shop.enums.EnumWithdrawStatus;
import com.zsk.shop.enums.EnumWithdrawType;
import com.zsk.shop.enums.ServiceKeyTypeEnum;
import com.zsk.shop.mapper.ShopWithdrawApplyMapper;
import com.zsk.shop.model.params.GopWithdrawApplyListParams;
import com.zsk.shop.model.results.GopWithdrawApplyRecordResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ljh
 * @create 2021/5/17 09:54
 */
@Service
public class WithdrawApplyService extends ServiceImpl<ShopWithdrawApplyMapper, ShopWithdrawApply> {

    private static final Logger logger = LoggerFactory.getLogger(WithdrawApplyService.class);

    @Resource
    private UserAccountService userAccountService;

    @Resource
    private ShopUserService userService;

    @Resource
    private GopUserService gopUserService;

    @Autowired
    private WeixinPayConfig wxPayService;

    @Resource
    private AliPayAccountUserService aliPayAccountUserService;
    @Resource
    private BankCardService bankCardService;

    @Resource
    private SmsService smsService;

    /**
     * 提现申请
     *
     * @author Ys
     * @date 2021/5/18 16:30
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse withdraw(Integer applyType, String bankCardNumber, BigDecimal money) {
        String userNo = HttpContext.getUserNo();
        ShopUser user = userService.queryByUserNo(userNo);
        BigDecimal difChargeMoney = calculationDifChargeUser(money); //BigDecimal.ZERO.setScale(2, BigDecimal.ROUND_HALF_UP);
        ShopUserAccount userAccount = userAccountService.getUserAccountByUserNo(userNo);
        if (ToolUtil.isNotEmpty(userAccount) &&
                userAccount.getNowBalance().subtract(userAccount.getTotalFrozen()).compareTo(money) >= 0) {
            ShopWithdrawApply withdrawApply = new ShopWithdrawApply();
            withdrawApply.setUserNo(userNo);
            withdrawApply.setApplyType(applyType);
            String trueName = user.getTrueName();
//            if (ToolUtil.isEmpty(trueName)) {
//                return BaseResponse.error("该账号暂未实名认证不支持提现,请联系管理员。");
//            }
            withdrawApply.setTrueName(trueName);
            withdrawApply.setStatus(EnumWithdrawStatus.ON.getCode());
            if (applyType.equals(EnumWithdrawType.CARD.getCode())) {
                //查询默认银行卡
                BankCardUser bankCardUser;
                if (ToolUtil.isNotEmpty(bankCardNumber)) {
                    bankCardUser = bankCardService.getByBankCardNumber(bankCardNumber);
                } else {
                    bankCardUser = bankCardService.getDefaultBankCardInfo(userNo);
                }
                withdrawApply.setBankCardId(bankCardUser.getBankCardId());
                withdrawApply.setPhone(bankCardUser.getPhone());
            } else if (applyType.equals(EnumWithdrawType.WECHAT.getCode())) {
                //2微信
                if (ToolUtil.isEmpty(user.getWxUnionId())) {
                    return BaseResponse.error("当前账号未授权微信");
                }
                withdrawApply.setMiniOpenId(user.getWxMiniOpenId());
                //微信直接提现
//                this.transferByWx(withdrawApply.getWithdrawApplyNo(), user.getWxMiniOpenId(), name, difChargeMoney);
//                withdrawApply.setStatus(EnumWithdrawStatus.SUCCESS.getCode());
            } else if (applyType.equals(EnumWithdrawType.ALIPAY.getCode())) {
                //根据填写支付宝账户
                AliPayAccountUser alipayAccountUser = aliPayAccountUserService.getByUser(userNo);
                if (ToolUtil.isEmpty(alipayAccountUser)) {
                    return BaseResponse.error("当前账号未设置支付宝提现账号");
                }
                withdrawApply.setAliAccountName(alipayAccountUser.getAlipayAccount());
            } else {
                return BaseResponse.error("当前不支持该提现方式。");
            }
            String withdrawApplyNo = RedisUtil.getServiceKeyHaveDateByType(ServiceKeyTypeEnum.WITHDRAW_APPLY.getValue());
            withdrawApply.setWithdrawApplyNo(withdrawApplyNo);
            withdrawApply.setWithdrawMoney(money);
            //提现成功后再更新当前数据
            withdrawApply.setBeforeMoney(userAccount.getNowBalance());
            withdrawApply.setAfterMoney(userAccount.getNowBalance().subtract(money).setScale(2, BigDecimal.ROUND_HALF_UP));
            withdrawApply.setDifChargeMoney(difChargeMoney);
            withdrawApply.setReceivedMoney(money.subtract(difChargeMoney).setScale(2, BigDecimal.ROUND_HALF_UP));
            withdrawApply.setApplyTime(new Date());
            this.save(withdrawApply);
            if (withdrawApply.getStatus().equals(EnumWithdrawStatus.ON.getCode())) {
                //提现冻结
                userAccountService.withdraw(money, userNo, withdrawApply.getId());
                //短信通知财务有人申请提现
                smsService.askSendFinanceSms();
                return BaseResponse.success("提现申请成功");
            }
            return BaseResponse.success("提现操作成功");
        } else {
            return BaseResponse.error("账户余额不足");
        }
    }

    /**
     * 提现
     *
     * @param outNo      提现编号
     * @param miniOpenId 对应openid
     * @param realName   提现真实姓名
     * @param amount     提现金额
     * @return
     */
    public String transferByWx(String outNo, String miniOpenId, String realName, BigDecimal amount) {
        if (ToolUtil.isOneEmpty(miniOpenId)) {
            return "未绑定微信";
        }
        TransferOrder order = new TransferOrder();
        order.setOutNo(outNo);
        order.setPayeeAccount(miniOpenId);
        order.setPayeeName(realName);
        order.setAmount(amount);
        if (!Constant.isProd()) {
            order.setAmount(new BigDecimal(0.2));
        }
        //转账到余额
        order.setTransferType(WxTransferType.TRANSFERS);
        Map<String, Object> map = wxPayService.getPayServiceMINI().transfer(order);
        logger.info("微信小程序提现反馈" + JSON.toJSONString(map));
        return PayUtil.wxHandldMsg(map);
    }

    /**
     * 提现记录列表
     *
     * @param params 列表筛选条件
     * @return
     * @author Ys
     * @date 2021/5/17 15:13
     */
    public BaseResponse<List<GopWithdrawApplyRecordResult>> getWithdrawApplyList(GopWithdrawApplyListParams params) {
        Page pageContext = BasePageFactory.defaultPage(params.getPage(), params.getLimit());
        List<String> userNos = null;
        if (!ToolUtil.isAllEmpty(params.getPhone(), params.getUserName())) {
            LambdaQueryWrapper<ShopUser> userQueryWrapper = new LambdaQueryWrapper<>();
            if (ToolUtil.isNotEmpty(params.getPhone())) {
                userQueryWrapper.like(ShopUser::getPhone, params.getPhone());
            }
            if (ToolUtil.isNotEmpty(params.getUserName())) {
                userQueryWrapper.like(ShopUser::getWxNickName, params.getUserName());
            }
            userQueryWrapper.isNotNull(ShopUser::getPhone);
            userQueryWrapper.orderByDesc(ShopUser::getCreateTime);
            List<ShopUser> userList = userService.list(userQueryWrapper);
            userNos = userList.stream().map(ShopUser::getUserNo).collect(Collectors.toList());
            userService.list(userQueryWrapper);
        }
        LambdaQueryWrapper<ShopWithdrawApply> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.ge(ShopWithdrawApply::getStatus, EnumWithdrawStatus.SUCCESS.getCode());
        if (ToolUtil.isNotEmpty(userNos)) {
            queryWrapper.in(ShopWithdrawApply::getUserNo, userNos);
        }
        if (ToolUtil.isNotEmpty(params.getStatus())) {
            queryWrapper.eq(ShopWithdrawApply::getStatus, Integer.parseInt(params.getStatus()));
        }
        if (!ToolUtil.isOneEmpty(params.getCreateTime(), params.getEndTime())) {
            queryWrapper.apply("UNIX_TIMESTAMP(apply_time) >= UNIX_TIMESTAMP('" + DateUtils.getDateStart(params.getCreateTime()) + "')");
            queryWrapper.apply("UNIX_TIMESTAMP(apply_time) <= UNIX_TIMESTAMP('" + DateUtils.getDateEnd(params.getEndTime()) + "')");
        }
        queryWrapper.orderByDesc(ShopWithdrawApply::getId);
        IPage page = this.page(pageContext, queryWrapper);
        List<GopWithdrawApplyRecordResult> applyList = EntityConvertUtils.convertAListToBList(page.getRecords(), GopWithdrawApplyRecordResult.class);
        for (GopWithdrawApplyRecordResult result : applyList){
            if(ToolUtil.isNotEmpty(result.getBankCardId())){
                BankCardUser cardUser = bankCardService.getByBankCardNumber(result.getBankCardId());
                if(ToolUtil.isNotEmpty(cardUser)){
                    result.setBankName(cardUser.getBankName());
                    result.setSubName(cardUser.getSubName());
                }
            }
        }
        applyList = getWithdrawApplyRecordFullInfo(applyList);
        page.setRecords(applyList);
        return BasePageFactory.createPageInfo(page);
    }

    /**
     * 审核
     *
     * @param id           列表主键
     * @param status       0待运营审核   1提现申请中 2提现成功 3拒绝
     * @param reviewReason 理由
     * @return
     * @author Ys
     * @date 2021/5/17 15:24
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse updateStatus(Long id, Integer status, String reviewReason) {
        ShopWithdrawApply shopWithdrawApply = this.getById(id);
        if (ToolUtil.isNotEmpty(shopWithdrawApply)) {
            //如果记录状态已审核则不操作
            if (shopWithdrawApply.getStatus().equals(EnumWithdrawStatus.SUCCESS.getCode()) ||
                    shopWithdrawApply.getStatus().equals(EnumWithdrawStatus.FAIL.getCode())) {
                return BaseResponse.error("该数据已审核过");
            }
            ShopUserAccount userAccount = userAccountService.getUserAccountByUserNo(shopWithdrawApply.getUserNo());
            shopWithdrawApply.setId(id);
            shopWithdrawApply.setStatus(status);
            shopWithdrawApply.setReviewUserNo(HttpContext.getUserNo());
            shopWithdrawApply.setReviewTime(new Date());
            shopWithdrawApply.setBeforeMoney(userAccount.getNowBalance());
            if (status.equals(EnumWithdrawStatus.SUCCESS.getCode())) {
                shopWithdrawApply.setAfterMoney(
                        userAccount.getNowBalance().subtract(shopWithdrawApply.getWithdrawMoney())
                                .setScale(2, BigDecimal.ROUND_HALF_UP));
                if (shopWithdrawApply.getApplyType().equals(EnumWithdrawType.CARD.getCode())) {
                    //审核时：支付宝直接走支付宝提现
                    shopWithdrawApply.setStatus(EnumWithdrawStatus.SUCCESS.getCode());
                    this.updateById(shopWithdrawApply);
                } else if (shopWithdrawApply.getApplyType().equals(EnumWithdrawType.WECHAT.getCode())) {
                    //审核时：微信直接走微信提现
                    // TODO: 2021/12/9 如果微信【付款到零钱】功能可以开通则放开权限，前期打钱后审核数据
//                try {
//                    String response = this.transferByWx(shopWithdrawApply.getWithdrawApplyNo(), shopWithdrawApply.getMiniOpenId()
//                            , shopWithdrawApply.getTrueName(), shopWithdrawApply.getReceivedMoney());
//                    //如果有值说明提现失败，提现申请被驳回
//                    if (ToolUtil.isNotEmpty(response)) {
//                        status = EnumWithdrawStatus.FAIL.getCode();
//                        shopWithdrawApply.setStatus(status);
//                        shopWithdrawApply.setReviewReason(response);
//                        this.updateById(shopWithdrawApply);
//                        throw new NoMsgException(500, "当前企业微信账户支付功能出错：" + response);
//                    }
//                } catch (NoMsgException e) {
//                    throw new BizException(500, e.getErrorMessage());
//                }
                } else if (shopWithdrawApply.getApplyType().equals(EnumWithdrawType.ALIPAY.getCode())) {
                    //审核时：支付宝直接走支付宝提现
                    // TODO: 2021/12/13 支付宝账户暂时没有接入
//                    try {
//                        AlipayFundTransUniTransferResponse response = fundTransUniTransfer.aliTransfer(
//                                shopWithdrawApply.getWithdrawApplyNo(), shopWithdrawApply.getReceivedMoney()
//                                , shopWithdrawApply.getAliAccountName(), shopWithdrawApply.getTrueName(), "");
//                        //如果有值说明提现失败，提现申请被驳回
//                        if (ToolUtil.isNotEmpty(response)) {
//                            if (response.getSubCode().equals("PAYER_BALANCE_NOT_ENOUGH")) {
//                                throw new NoMsgException(500, "目前系统有误，请重新发起申请：" + response.getSubMsg());
//                            }
//                            status = EnumWithdrawStatus.FAIL.getCode();
//                            shopWithdrawApply.setStatus(status);
//                            shopWithdrawApply.setReviewReason(response.getSubMsg());
//                        }
//                    } catch (AlipayApiException e) {
//                        throw new BizException(500, e.getErrMsg());
//                    }
                } else {
                    throw new BizException(500, "提现方式不正确。");
                }
            } else if (status.equals(EnumWithdrawStatus.FAIL.getCode())) {
                shopWithdrawApply.setReviewReason(reviewReason);
                shopWithdrawApply.setAfterMoney(userAccount.getNowBalance());
            }
            if (this.updateById(shopWithdrawApply)) {
                //扣除用户冻结，提现成功
                if (status.equals(EnumWithdrawStatus.SUCCESS.getCode())) {
                    userAccountService.withdrawSuccess(shopWithdrawApply);
                } else if (status.equals(EnumWithdrawStatus.FAIL.getCode())) {
                    userAccountService.withdrawFail(shopWithdrawApply);
                }
                return BaseResponse.success(shopWithdrawApply.getReviewReason());
            } else {
                return BaseResponse.error("数据错误");
            }
        }
        return BaseResponse.error("记录不存在");
    }

    private List<GopWithdrawApplyRecordResult> getWithdrawApplyRecordFullInfo(List<GopWithdrawApplyRecordResult> applyList) {
        List<String> operateUserNos = applyList.stream().map(GopWithdrawApplyRecordResult::getReviewUserNo).distinct().collect(Collectors.toList());
        List<String> userNos = applyList.stream().map(GopWithdrawApplyRecordResult::getUserNo).distinct().collect(Collectors.toList());
        List<GopUser> operateUserList = gopUserService.queryNameByNos(operateUserNos);
        List<ShopUser> userList = userService.listByNos(userNos);
        for (GopWithdrawApplyRecordResult record : applyList) {
            GopUser operateUser = operateUserList.stream().filter(x -> x.getUserNo().equals(record.getReviewUserNo())).findFirst().orElse(new GopUser());
            ShopUser user = userList.stream().filter(x -> x.getUserNo().equals(record.getUserNo())).findFirst().orElse(new ShopUser());
            record.setUserName(user.getNickName());
            record.setPhone(user.getPhone());
            record.setReviewUserName(operateUser.getName());
            record.setStatusStr(EnumWithdrawStatus.getNameByCode(record.getStatus()));
            Integer applyType = record.getApplyType();
            record.setApplyTypeStr(EnumWithdrawType.getNameByCode(applyType));
            record.setWithdrawMoneyStr(record.getWithdrawMoney().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
            record.setDifChargeMoneyStr(record.getDifChargeMoney().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
            record.setReceivedMoneyStr(record.getReceivedMoney().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
            String accountType = applyType.equals(EnumWithdrawType.WECHAT.getCode()) ? EnumWithdrawType.WECHAT.getValue() : "";
            record.setAccountType(accountType);
        }
        return applyList;
    }

    /**
     * 提现抽成
     *
     * @param money
     * @return
     */
    private static BigDecimal calculationDifChargeUser(BigDecimal money) {
        return money.multiply(BigDecimal.valueOf(0.05)).setScale(2, BigDecimal.ROUND_HALF_UP);
//        return BigDecimal.ZERO.setScale(2, BigDecimal.ROUND_HALF_UP);
    }

}
